#pragma region Copyright
/// <copyright>
/// Copyright (c) 2007 Ilia Shramko.
/// Released under the terms of the GNU Lesser General Public License.
/// </copyright>
#pragma endregion

#pragma once

#define GET_ENUM_STR(ev) case ev: result = #ev; break;

static const wchar_t* FileNameSpace = L"file";
static const size_t FileNameSpaceSize = 4;
static const wchar_t* FileUrlPrefix = L"file:///";

static const wchar_t* HttpNameSpace = L"http";
static const size_t HttpNameSpaceSize = 4;

static const wchar_t* OSHNameSpace = L"osh";
static const size_t OSHNameSpaceSize = 3;

static const wchar_t* OSHNameSpaceAndHost = L"osh://localhost";
static const size_t OSHNameSpaceAndHostSize = 15;

static const wchar_t* OSHSecurityDomain = L"osh:";

static const wchar_t* OSHSecurityURL = L"osh:";

// {ACF27B02-D339-4ea7-9145-51D4B7ABF158}
static const GUID CLSID_OSHProtocolHandler =
	{ 0xacf27b02, 0xd339, 0x4ea7, { 0x91, 0x45, 0x51, 0xd4, 0xb7, 0xab, 0xf1, 0x58 } };

class OSHProtocol;

//*********************************************************
// OSHProtocolHandler
//*********************************************************
class ATL_NO_VTABLE OSHProtocolHandler : 
	public CComObjectRootEx<CComMultiThreadModel>,
	public CComCoClass<OSHProtocolHandler>,
	public IInternetProtocol,
	public IInternetProtocolInfo
{
public:

	static const char* OSHSecurityId;
	static const int OSHSecurityIdSize;
	static const int OSHSecurityZone;

private:
	friend class OSHProtocolHandlerSink;


	#pragma region OSHProtocolHandlerSink
	// This is a separate from OSHProtocolHandler class
	// implementing IInternetProtocolSink & IInternetBindInfo
	// for IInternetProtocol helper class.
	// Separation was done to prevent circular references between
	// OSHProtocolHandler and helper classes.
	class ATL_NO_VTABLE OSHProtocolHandlerSink : 
		public CComObjectRootEx<CComMultiThreadModel>,
		public CComCoClass<OSHProtocolHandlerSink>,
		public IInternetProtocolSink,
		public IInternetBindInfo,
		public IServiceProvider,
		public IHttpNegotiate2
	{
	private:
		CComPtr<IInternetProtocolSink> _clientProtocolSink;
		CComPtr<IInternetBindInfo> _clientBindInfo;
		CComPtr<IServiceProvider> _clientServiceProvider;
		CComPtr<IHttpNegotiate> _clientHttpNegotiate;
		CComPtr<IHttpNegotiate2> _clientHttpNegotiate2;

	public:
		OSHProtocolHandlerSink()
		{
			ATLTRACE_TS(atlTraceIE, TraceLevel::Verbose,
				"[%08X] OSHProtocolHandlerSink::OSHProtocolHandlerSink\r\n", this);
		}

		virtual ~OSHProtocolHandlerSink()
		{
			ATLTRACE_TS(atlTraceIE, TraceLevel::Verbose,
				"[%08X] OSHProtocolHandlerSink::~OSHProtocolHandlerSink\r\n", this);
		}

		BEGIN_COM_MAP(OSHProtocolHandlerSink)
			COM_INTERFACE_ENTRY(IInternetProtocolSink)
			COM_INTERFACE_ENTRY(IInternetBindInfo)
			COM_INTERFACE_ENTRY(IServiceProvider)
			COM_INTERFACE_ENTRY(IHttpNegotiate)
			COM_INTERFACE_ENTRY(IHttpNegotiate2)
		END_COM_MAP()

		static HRESULT WINAPI InternalQueryInterface(void* pThis,
			const _ATL_INTMAP_ENTRY* pEntries, REFIID iid, void** ppvObject)
		{
			HRESULT hr = 
				CComObjectRootEx<CComMultiThreadModel>::InternalQueryInterface(pThis, pEntries, iid, ppvObject);

			HRESULT hr2 = E_NOINTERFACE;
			if(SUCCEEDED(hr) && iid == __uuidof(IServiceProvider))
			{
				OSHProtocolHandlerSink* thisObj = reinterpret_cast<OSHProtocolHandlerSink*>(pThis);
				hr2 = thisObj->_clientProtocolSink->QueryInterface(&(thisObj->_clientServiceProvider));
			}

			wchar_t iidString[100] = {0};
			StringFromGUID2(iid, iidString, 100);
			ATLTRACE_TS(atlTraceIE, TraceLevel::Verbose,
				"OSHProtocolHandlerSink::InternalQueryInterface(%S) : 0x%08X (0x%08X)\r\n", iidString, hr, hr2);

			return hr;
		}

		void SetInterfaces(IInternetProtocolSink* clientProtocolSink, IInternetBindInfo* clientBindInfo)
		{
			_clientProtocolSink = clientProtocolSink;
			_clientBindInfo = clientBindInfo;
		}

		//*********************************************************
		// IHttpNegotiate
		//*********************************************************
		STDMETHOD(BeginningTransaction)(LPCWSTR szURL, LPCWSTR szHeaders,
			DWORD dwReserved, LPWSTR* pszAdditionalHeaders)
		{
			ATLASSERT(_clientHttpNegotiate != NULL);

			HRESULT hr = _clientHttpNegotiate->BeginningTransaction(
				szURL, szHeaders, dwReserved, pszAdditionalHeaders);

			ATLTRACE_TS(atlTraceIE, TraceLevel::Verbose,
				"IHttpNegotiate::BeginningTransaction(%S) : 0x%08X\r\n"
				"--- Request headers\r\n%S\r\n"
				"--- Additional headers\r\n%S\r\n",
				szURL, hr, szHeaders, pszAdditionalHeaders == NULL ? NULL : *pszAdditionalHeaders);

			return hr;
		}

		STDMETHOD(OnResponse)(DWORD dwResponseCode, LPCWSTR szResponseHeaders,
			LPCWSTR szRequestHeaders, LPWSTR* pszAdditionalRequestHeaders)
		{
			ATLASSERT(_clientHttpNegotiate != NULL);

			HRESULT hr = _clientHttpNegotiate->OnResponse(dwResponseCode, szResponseHeaders,
				szRequestHeaders, pszAdditionalRequestHeaders);

			ATLTRACE_TS(atlTraceIE, TraceLevel::Verbose,
				"IHttpNegotiate::OnResponse(%d) : 0x%08X\r\n"
				"--- Request headers\r\n%S\r\n"
				"--- Response headers\r\n%S\r\n"
				"--- Additional request headers\r\n%S\r\n",
				dwResponseCode, hr, szRequestHeaders, szResponseHeaders,
				pszAdditionalRequestHeaders == NULL ? NULL : *pszAdditionalRequestHeaders);
			
			return hr;
		}


		//*********************************************************
		// IHttpNegotiate2
		//*********************************************************
		STDMETHOD(GetRootSecurityId)(BYTE* pbSecurityId, DWORD* pcbSecurityId, DWORD_PTR dwReserved)
		{
			ATLASSERT(_clientHttpNegotiate2 != NULL);

			HRESULT hr = _clientHttpNegotiate2->GetRootSecurityId(pbSecurityId, pcbSecurityId, dwReserved);

			ATLTRACE_TS(atlTraceIE, TraceLevel::Verbose,
				"IHttpNegotiate2::GetRootSecurityId(0x%08X, %d) : 0x%08X\r\n",
				pbSecurityId, (pcbSecurityId ? *pcbSecurityId : 0), hr);

			//memcpy(reinterpret_cast<char*>(pbSecurityId), OSHSecurityId, OSHSecurityIdSize);
			//*pcbSecurityId = OSHSecurityIdSize;

			return hr;
		}


		//*********************************************************
		// IServiceProvider
		//*********************************************************
		STDMETHOD(QueryService)(REFGUID guidService, REFIID riid, void** ppv)
		{
			if(ppv == NULL) return E_POINTER;
			*ppv = NULL;

			wchar_t guidString[100] = {0};
			StringFromGUID2(guidService, guidString, 100);

			wchar_t iidString[100] = {0};
			StringFromGUID2(riid, iidString, 100);

			HRESULT hr = E_NOINTERFACE;
			if(_clientServiceProvider != NULL && riid == __uuidof(IHttpNegotiate))
			{
				hr = _clientServiceProvider->QueryService(guidService, &_clientHttpNegotiate);
				IHttpNegotiate* result = static_cast<IHttpNegotiate*>(this);
				result->AddRef();
				*ppv = result;
			}
			if(_clientServiceProvider != NULL && riid == __uuidof(IHttpNegotiate2))
			{
				hr = _clientServiceProvider->QueryService(guidService, &_clientHttpNegotiate2);
				IHttpNegotiate2* result = static_cast<IHttpNegotiate2*>(this);
				result->AddRef();
				*ppv = result;
			}

			ATLTRACE_TS(atlTraceIE, TraceLevel::Verbose,
				"IServiceProvider::QueryService(%S, %S) : 0x%08X\r\n", guidString, iidString, hr);

			return hr;
		}


		//*********************************************************
		// IInternetProtocolSink
		//*********************************************************
		STDMETHOD(Switch)(/* [in] */ PROTOCOLDATA* pProtocolData)
		{
			ATLASSERT(_clientProtocolSink != NULL);
			if(_clientProtocolSink == NULL)
				return E_UNEXPECTED;

			HRESULT hr = _clientProtocolSink->Switch(pProtocolData);
			
			ATLTRACE_TS(atlTraceIE, TraceLevel::Verbose,
				"IInternetProtocolSink::Switch() : 0x%08X\r\n", hr);

			return hr;
		}

		STDMETHOD(ReportProgress)(/* [in] */ ULONG ulStatusCode, /* [in] */ LPCWSTR szStatusText)
		{
			ATLASSERT(_clientProtocolSink != NULL);
			if(_clientProtocolSink == NULL)
				return E_UNEXPECTED;

			HRESULT hr = _clientProtocolSink->ReportProgress(ulStatusCode, szStatusText);

			ATLTRACE_TS(atlTraceIE, TraceLevel::Verbose,
				"IInternetProtocolSink::ReportProgress(%d=%s, %S) : 0x%08X\r\n",
				ulStatusCode, GetBindStatus(ulStatusCode), szStatusText, hr);

			return hr;
		}

		STDMETHOD(ReportData)(/* [in] */ DWORD grfBSCF, /* [in] */ ULONG ulProgress, /* [in] */ ULONG ulProgressMax)
		{
			ATLASSERT(_clientProtocolSink != NULL);
			if(_clientProtocolSink == NULL)
				return E_UNEXPECTED;

			HRESULT hr = _clientProtocolSink->ReportData(grfBSCF, ulProgress, ulProgressMax);

			ATLTRACE_TS(atlTraceIE, TraceLevel::Verbose,
				"IInternetProtocolSink::ReportData(%d, %d) : 0x%08X\r\n", ulProgress, ulProgressMax, hr);

			return hr;
		}

		STDMETHOD(ReportResult)(/* [in] */ HRESULT hrResult, /* [in] */ DWORD dwError, /* [in] */ LPCWSTR szResult)
		{
			ATLASSERT(_clientProtocolSink != NULL);
			if(_clientProtocolSink == NULL)
				return E_UNEXPECTED;

			HRESULT hr = _clientProtocolSink->ReportResult(hrResult, dwError, szResult);

			ATLTRACE_TS(atlTraceIE, TraceLevel::Verbose,
				"IInternetProtocolSink::ReportResult(0x%X, %d, %S) : 0x%08X\r\n",
				hrResult, dwError, szResult, hr);

			return hr;
		}


		//*********************************************************
		// IInternetBindInfo
		//*********************************************************
		STDMETHOD(GetBindInfo)(/* [out] */ DWORD* grfBINDF, /* [unique][out][in] */ BINDINFO* pbindinfo)
		{
			ATLASSERT(_clientBindInfo != NULL);
			if(_clientBindInfo == NULL)
				return E_UNEXPECTED;

			HRESULT hr = _clientBindInfo->GetBindInfo(grfBINDF, pbindinfo);

			ATLTRACE_TS(atlTraceIE, TraceLevel::Verbose,
				"IInternetBindInfo::GetBindInfo(0x%X) : 0x%08X\r\n", (grfBINDF ? *grfBINDF : 0), hr);

			return hr;
		}

		STDMETHOD(GetBindString)(/* [in] */ ULONG ulStringType, /* [out][in] */ LPOLESTR* ppwzStr,
			/* [in] */ ULONG cEl, /* [out][in] */ ULONG* pcElFetched)
		{

			ATLASSERT(_clientBindInfo != NULL);
			if(_clientBindInfo == NULL)
				return E_UNEXPECTED;

			HRESULT hr = _clientBindInfo->GetBindString(ulStringType, ppwzStr, cEl, pcElFetched);

#ifdef ATLTRACE_TS
			if(FAILED(hr))
				ATLTRACE_TS(atlTraceIE, TraceLevel::Verbose,
					"IInternetBindInfo::GetBindString(%s) failed.\r\n", GetBindStringId(ulStringType));
			else
			{
				ATLTRACE_TS(atlTraceIE, TraceLevel::Verbose,
					"IInternetBindInfo::GetBindString(%s) => %d items:",
					GetBindStringId(ulStringType), *pcElFetched);

				for(ULONG i = 0; i < *pcElFetched; i++)
					ATLTRACE(atlTraceIE, TraceLevel::Verbose, "%S\r\n", ppwzStr[i]);

				if(*pcElFetched == 0)
					ATLTRACE(atlTraceIE, TraceLevel::Verbose, "\r\n");
			}
#endif

			return hr;
		}

		const char* GetBindStringId(ULONG bindStringId)
		{
			const char* result = "UNKNOWN";
			if(bindStringId == BINDSTRING_HEADERS) result = "BINDSTRING_HEADERS";
			else if(bindStringId == BINDSTRING_ACCEPT_MIMES) result = "BINDSTRING_ACCEPT_MIMES";
			else if(bindStringId == BINDSTRING_EXTRA_URL) result = "BINDSTRING_EXTRA_URL";
			else if(bindStringId == BINDSTRING_LANGUAGE) result = "BINDSTRING_LANGUAGE";
			else if(bindStringId == BINDSTRING_USERNAME) result = "BINDSTRING_USERNAME";
			else if(bindStringId == BINDSTRING_PASSWORD) result = "BINDSTRING_PASSWORD";
			else if(bindStringId == BINDSTRING_UA_PIXELS) result = "BINDSTRING_UA_PIXELS";
			else if(bindStringId == BINDSTRING_UA_COLOR) result = "BINDSTRING_UA_COLOR";
			else if(bindStringId == BINDSTRING_OS) result = "BINDSTRING_OS";
			else if(bindStringId == BINDSTRING_USER_AGENT) result = "BINDSTRING_USER_AGENT";
			else if(bindStringId == BINDSTRING_ACCEPT_ENCODINGS) result = "BINDSTRING_ACCEPT_ENCODINGS";
			else if(bindStringId == BINDSTRING_POST_COOKIE) result = "BINDSTRING_POST_COOKIE";
			else if(bindStringId == BINDSTRING_POST_DATA_MIME) result = "BINDSTRING_POST_DATA_MIME";
			else if(bindStringId == BINDSTRING_URL) result = "BINDSTRING_URL";
			else if(bindStringId == BINDSTRING_IID) result = "BINDSTRING_IID";
			else if(bindStringId == BINDSTRING_FLAG_BIND_TO_OBJECT) result = "BINDSTRING_FLAG_BIND_TO_OBJECT";
			else if(bindStringId == BINDSTRING_PTR_BIND_CONTEXT) result = "BINDSTRING_PTR_BIND_CONTEXT";
			return result;
		}

		const char* GetBindStatus(ULONG bindStatus)
		{
			const char* result = NULL;
			switch(bindStatus)
			{
			GET_ENUM_STR(BINDSTATUS_FINDINGRESOURCE);
			GET_ENUM_STR(BINDSTATUS_CONNECTING);
			GET_ENUM_STR(BINDSTATUS_REDIRECTING);
			GET_ENUM_STR(BINDSTATUS_BEGINDOWNLOADDATA);
			GET_ENUM_STR(BINDSTATUS_DOWNLOADINGDATA);
			GET_ENUM_STR(BINDSTATUS_ENDDOWNLOADDATA);
			GET_ENUM_STR(BINDSTATUS_BEGINDOWNLOADCOMPONENTS);
			GET_ENUM_STR(BINDSTATUS_INSTALLINGCOMPONENTS);
			GET_ENUM_STR(BINDSTATUS_ENDDOWNLOADCOMPONENTS);
			GET_ENUM_STR(BINDSTATUS_USINGCACHEDCOPY);
			GET_ENUM_STR(BINDSTATUS_SENDINGREQUEST);
			GET_ENUM_STR(BINDSTATUS_CLASSIDAVAILABLE);
			GET_ENUM_STR(BINDSTATUS_MIMETYPEAVAILABLE);
			GET_ENUM_STR(BINDSTATUS_CACHEFILENAMEAVAILABLE);
			GET_ENUM_STR(BINDSTATUS_BEGINSYNCOPERATION);
			GET_ENUM_STR(BINDSTATUS_ENDSYNCOPERATION);
			GET_ENUM_STR(BINDSTATUS_BEGINUPLOADDATA);
			GET_ENUM_STR(BINDSTATUS_UPLOADINGDATA);
			//GET_ENUM_STR(BINDSTATUS_ENDUPLOADINGDATA);
			GET_ENUM_STR(BINDSTATUS_PROTOCOLCLASSID);
			GET_ENUM_STR(BINDSTATUS_ENCODING);
			//GET_ENUM_STR(BINDSTATUS_VERFIEDMIMETYPEAVAILABLE);
			GET_ENUM_STR(BINDSTATUS_CLASSINSTALLLOCATION);
			GET_ENUM_STR(BINDSTATUS_DECODING);
			GET_ENUM_STR(BINDSTATUS_LOADINGMIMEHANDLER);
			GET_ENUM_STR(BINDSTATUS_CONTENTDISPOSITIONATTACH);
			GET_ENUM_STR(BINDSTATUS_FILTERREPORTMIMETYPE);
			GET_ENUM_STR(BINDSTATUS_CLSIDCANINSTANTIATE);
			GET_ENUM_STR(BINDSTATUS_IUNKNOWNAVAILABLE);
			GET_ENUM_STR(BINDSTATUS_DIRECTBIND);
			GET_ENUM_STR(BINDSTATUS_RAWMIMETYPE);
			GET_ENUM_STR(BINDSTATUS_PROXYDETECTING);
			GET_ENUM_STR(BINDSTATUS_ACCEPTRANGES);
			GET_ENUM_STR(BINDSTATUS_COOKIE_SENT);
			GET_ENUM_STR(BINDSTATUS_COMPACT_POLICY_RECEIVED);
			GET_ENUM_STR(BINDSTATUS_COOKIE_SUPPRESSED);
			GET_ENUM_STR(BINDSTATUS_COOKIE_STATE_UNKNOWN);
			GET_ENUM_STR(BINDSTATUS_COOKIE_STATE_ACCEPT);
			GET_ENUM_STR(BINDSTATUS_COOKIE_STATE_REJECT);
			GET_ENUM_STR(BINDSTATUS_COOKIE_STATE_PROMPT);
			GET_ENUM_STR(BINDSTATUS_COOKIE_STATE_LEASH);
			GET_ENUM_STR(BINDSTATUS_COOKIE_STATE_DOWNGRADE);
			GET_ENUM_STR(BINDSTATUS_POLICY_HREF);
			GET_ENUM_STR(BINDSTATUS_P3P_HEADER);
			GET_ENUM_STR(BINDSTATUS_SESSION_COOKIE_RECEIVED);
			GET_ENUM_STR(BINDSTATUS_PERSISTENT_COOKIE_RECEIVED);
			GET_ENUM_STR(BINDSTATUS_SESSION_COOKIES_ALLOWED);
			//GET_ENUM_STR(BINDSTATUS_CACHECONTROL);
			//GET_ENUM_STR(BINDSTATUS_CONTENTDISPOSITIONFILENAME);
			//GET_ENUM_STR(BINDSTATUS_MIMETEXTPLAINMISMATCH);
			//GET_ENUM_STR(BINDSTATUS_PUBLISHERAVAILABLE);
			//GET_ENUM_STR(BINDSTATUS_DISPLAYNAMEAVAILABLE);
			default:
				result = "UNKNOWN";
			}
			return result;
		}
	};
	#pragma endregion


private:
	CComBSTR _basePath;

	CComPtr<IInternetProtocol> _helperProtocol;
	CComQIPtr<IInternetProtocolInfo> _helperProtocolInfo;

	CComPtr<IInternetProtocol> _fileHelperProtocol;
	CComQIPtr<IInternetProtocolInfo> _fileHelperProtocolInfo;

	CComPtr<IInternetProtocol> _httpHelperProtocol;
	CComQIPtr<IInternetProtocolInfo> _httpHelperProtocolInfo;

	bool _usingHelperProtocol;

	CComPtr<OSHLibrary::IProtocolSink> _protocolSink;
	HttpResponse* _httpResponse;
	bool _locked;

	const char* GetParseUrlAction(PARSEACTION action);
	const char* GetQueryName(QUERYOPTION queryOption);
	bool IsOSHNamespace(LPCWSTR szUrl);
	bool ParseURL(LPCWSTR szUrl, CComBSTR& resultUrl,
		CComPtr<IInternetProtocol>& helperProtocol, CComPtr<IInternetProtocolInfo>& helperProtocolInfo);
	bool IsCustomProtocol(const wchar_t* url, const wchar_t* protocol, size_t protocolLength);
	HRESULT GetHttpNegotiate(IInternetProtocolSink* inetProtocolSink, IHttpNegotiate** httpNegotiate);
	//bool CheckAccessRights(const wchar_t* fileUrl, CString& filePath);
	HRESULT StartEx(LPCWSTR url, IInternetProtocolSink* inetProtocolSink,
		IInternetBindInfo* inetBindInfo, DWORD grfPI);
	HRESULT CreateHttpRequest(LPCWSTR url, IInternetBindInfo* inetBindInfo, HttpRequest** httpRequest);

public:
	OSHProtocolHandler();
	virtual ~OSHProtocolHandler();

	BEGIN_COM_MAP(OSHProtocolHandler)
		COM_INTERFACE_ENTRY(IInternetProtocol)
		COM_INTERFACE_ENTRY(IInternetProtocolInfo)
	END_COM_MAP()

	void Initialize(const wchar_t* basePath, OSHLibrary::IProtocolSink* protocolSink,
		IInternetProtocol* fileHelperProtocol, IInternetProtocol* httpHelperProtocol);
	//HRESULT ReportResult(HRESULT result, ULONG resultSize);


	//*********************************************************
	// IInternetProtocolInfo
	//*********************************************************
	STDMETHOD(ParseUrl)(/* [in] */ LPCWSTR pwzUrl, /* [in] */ PARSEACTION parseAction,
		/* [in] */ DWORD dwParseFlags, /* [out] */ LPWSTR pwzResult,
		/* [in] */ DWORD cchResult, /* [out] */ DWORD* pcchResult, /* [in] */ DWORD dwReserved);
	STDMETHOD(CombineUrl)(/* [in] */ LPCWSTR pwzBaseUrl, /* [in] */ LPCWSTR pwzRelativeUrl,
		/* [in] */ DWORD dwCombineFlags, /* [out] */ LPWSTR pwzResult,
		/* [in] */ DWORD cchResult, /* [out] */ DWORD* pcchResult, /* [in] */ DWORD dwReserved);
	STDMETHOD(CompareUrl)(/* [in] */ LPCWSTR pwzUrl1, /* [in] */ LPCWSTR pwzUrl2, /* [in] */ DWORD dwCompareFlags);
	STDMETHOD(QueryInfo)(/* [in] */ LPCWSTR pwzUrl, /* [in] */ QUERYOPTION queryOption,
		/* [in] */ DWORD dwQueryFlags, /* [size_is][out][in] */ LPVOID pBuffer,
		/* [in] */ DWORD cbBuffer, /* [out][in] */ DWORD* pcbBuf, /* [in] */ DWORD dwReserved);


	//*********************************************************
	// IInternetProtocolRoot
	//*********************************************************
	STDMETHOD(Start)(LPCWSTR szUrl, IInternetProtocolSink* pOIProtSink,
		IInternetBindInfo* pOIBindInfo, DWORD grfPI, HANDLE_PTR dwReserved);
	STDMETHOD(Continue)(PROTOCOLDATA* pProtocolData);
	STDMETHOD(Abort)(HRESULT hrReason, DWORD dwOptions);
	STDMETHOD(Terminate)(DWORD dwOptions);
	STDMETHOD(Suspend)();
	STDMETHOD(Resume)();


	//*********************************************************
	// IInternetProtocol
	//*********************************************************
	STDMETHOD(Read)(void* pv, ULONG cb, ULONG* pcbRead);
	STDMETHOD(Seek)(LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER* plibNewPosition);
	STDMETHOD(LockRequest)(DWORD dwOptions);
	STDMETHOD(UnlockRequest)();

};

// Works only with the following registry value:
// HKLM\Software\Microsoft\Windows\CurrentVersion\Internet Settings\ZoneMap\ProtocolDefaults\@osh = 2
__declspec(selectany) const char* OSHProtocolHandler::OSHSecurityId = "osh:";
__declspec(selectany) const int OSHProtocolHandler::OSHSecurityIdSize = 4;
__declspec(selectany) const int OSHProtocolHandler::OSHSecurityZone = 3;

